﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using OdaOperation.Extends;
using OdaOperation.Model;
using OdaOperation.Utils;
using Teigha.Core;
using Teigha.TD;

namespace OdaOperation.DB
{
    public class DbDatabase : IDisposable
    {
        private OdDbDatabase m_database;

        public OdDbDatabase Database => m_database;

        public DbDatabase(OdDbDatabase odDbDatabase)
        {
            m_database = odDbDatabase;
        }

        internal void CreateEntity(string layerName, Func<OdDbEntity> ac, StyleModel css)
        {
            if (!GetLayerState(layerName))
            {
                layerName = "0";
            }

            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction();
            try
            {
                OdDbEntity odDbEntity = ac();
                odDbEntity.setDatabaseDefaults(m_database);
                odDbEntity.setLayer(layerName, doSubents: false);
                OdCmColor odCmColor = new OdCmColor(OdCmEntityColor.Items_ColorMethod.kByLayer);
                odCmColor.isByLayer();
                odDbEntity.setColor(odCmColor);
                odDbEntity.setLineWeight(LineWeight.kLnWtByLayer);
                odDbEntity.setLinetype(m_database.getLinetypeByLayerId());
                odDbEntity.setLinetypeScale(100.0 / m_database.getLTSCALE());
                if (css != null)
                {
                    if (!string.IsNullOrEmpty(css.Color))
                    {
                        OdCmColor odCmColor2 = new OdCmColor();
                        string[] array = css.Color.Split(',');
                        OdCmColor odCmColor3 = new OdCmColor();
                        odCmColor3.setRGB(byte.Parse(array[0]), byte.Parse(array[1]), byte.Parse(array[2]));
                        odDbEntity.setColor(odCmColor3);
                    }

                    if (!string.IsNullOrEmpty(css.LineTypeName))
                    {
                        if (!LineTypeState(css.LineTypeName))
                        {
                            throw new Exception("线型" + css.LineTypeName + "不存在");
                        }

                        odDbEntity.setLinetype(css.LineTypeName);
                    }
                }

                AppendEntityToDatabase(m_database, odDbEntity);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        internal void CreateEntity(Action ac)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction();
            try
            {
                ac();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        public void Commit(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                m_database.Dispose();
                throw new Exception("保存路径不能为空！");
            }

            try
            {
                m_database.writeFile(path, SaveType.kDwg, m_database.version(), saveThumbnailImage: true);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                m_database.Dispose();
            }
        }

        internal OdDbObjectId AppendEntityToDatabase(OdDbDatabase db, OdDbEntity ent)
        {
            if (ent == null)
            {
                return null;
            }

            if (ent.blockId().openObject() == null)
            {
                OdDbObjectId odDbObjectId = ActiveBlockTableRecord(db);
                OdDbBlockTableRecord odDbBlockTableRecord = odDbObjectId.safeOpenObject(OpenMode.kForWrite) as OdDbBlockTableRecord;
                odDbBlockTableRecord.appendOdDbEntity(ent);
                return odDbObjectId;
            }

            return ent.blockId();
        }

        private OdDbObjectId ActiveBlockTableRecord(OdDbDatabase pDb)
        {
            OdDbObjectId odDbObjectId = pDb.getActiveLayoutBTRId();
            if (odDbObjectId == pDb.getPaperSpaceId())
            {
                OdDbViewport odDbViewport = pDb.activeViewportId().safeOpenObject() as OdDbViewport;
                if (odDbViewport.number() > 1)
                {
                    odDbObjectId = pDb.getModelSpaceId();
                }
            }

            return odDbObjectId;
        }

        public bool GetLayerState(string layerName)
        {
            OdDbLayerTable odDbLayerTable = (OdDbLayerTable)m_database.getLayerTableId().safeOpenObject(OpenMode.kForRead);
            if (odDbLayerTable.has(layerName))
            {
                return true;
            }

            return false;
        }

        internal void AddLayer(string layerName)
        {
            if (GetLayerState(layerName))
            {
                throw new Exception("图层" + layerName + "已经曾在不能重复创建");
            }

            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction();
            try
            {
                OdDbLayerTable odDbLayerTable = (OdDbLayerTable)m_database.getLayerTableId().safeOpenObject(OpenMode.kForRead);
                if (!odDbLayerTable.has(layerName))
                {
                    odDbLayerTable.upgradeOpen();
                    OdDbLayerTableRecord odDbLayerTableRecord = OdDbLayerTableRecord.createObject();
                    odDbLayerTableRecord.setName(layerName);
                    odDbLayerTableRecord.setColorIndex(7);
                    OdDbLinetypeTable odDbLinetypeTable = (OdDbLinetypeTable)m_database.getLinetypeTableId().safeOpenObject();
                    OdDbObjectId at = odDbLinetypeTable.getAt("CONTINUOUS");
                    odDbLayerTableRecord.setLinetypeObjectId(at);
                    OdDbObjectId odDbObjectId = odDbLayerTable.add(odDbLayerTableRecord);
                    odDbLayerTable.downgradeOpen();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        internal List<OdDbObjectId> AddLineType(string path, params string[] linTypeName)
        {
            if (!Path.GetExtension(path).Equals(".lin"))
            {
                throw new Exception("导入线型文件格不正确！");
            }

            if (!File.Exists(path))
            {
                throw new Exception("导入的文件不存在");
            }

            if (linTypeName.Length < 0)
            {
                throw new Exception("请添加线型的名称");
            }

            List<OdDbObjectId> list = new List<OdDbObjectId>();
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction();
            try
            {
                OdDbLinetypeTable odDbLinetypeTable = (OdDbLinetypeTable)m_database.getLinetypeTableId().safeOpenObject(OpenMode.kForRead);
                foreach (string item in linTypeName.Distinct())
                {
                    if (!odDbLinetypeTable.has(item))
                    {
                        m_database.loadLineTypeFile(item, path);
                        list.Add(odDbLinetypeTable.getAt(item));
                    }
                }

                return list;
            }
            catch (Exception innerException)
            {
                string text = "";
                foreach (string text2 in linTypeName)
                {
                    text = text + text2 + ";";
                }

                throw new Exception("线形添加失败" + text + ":" + path, innerException);
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        public bool LineTypeState(string lineTypeName)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction();
            try
            {
                OdDbLinetypeTable odDbLinetypeTable = (OdDbLinetypeTable)m_database.getLinetypeTableId().safeOpenObject(OpenMode.kForRead);
                if (odDbLinetypeTable.has(lineTypeName))
                {
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        internal bool SetLineTypeOnLayer(string layerName, string lineTypeName, LineWeight weight, string lineColorRgb)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction();
            try
            {
                OdDbLayerTable odDbLayerTable = (OdDbLayerTable)m_database.getLayerTableId().safeOpenObject(OpenMode.kForRead);
                OdDbLinetypeTable odDbLinetypeTable = (OdDbLinetypeTable)m_database.getLinetypeTableId().safeOpenObject(OpenMode.kForRead);
                if (odDbLayerTable.has(layerName))
                {
                    OdDbLayerTableRecord odDbLayerTableRecord = (OdDbLayerTableRecord)odDbLayerTable.getAt(layerName, OpenMode.kForWrite);
                    if (odDbLinetypeTable.has(lineTypeName))
                    {
                        OdDbObjectId at = odDbLinetypeTable.getAt(lineTypeName);
                        if (lineTypeName != null)
                        {
                            odDbLayerTableRecord.setLinetypeObjectId(at);
                        }
                    }

                    if (weight != LineWeight.kLnWtByLwDefault)
                    {
                        odDbLayerTableRecord.setLineWeight(weight);
                    }

                    if (!string.IsNullOrEmpty(lineColorRgb))
                    {
                        string[] array = lineColorRgb.Split(',');
                        OdCmColor odCmColor = new OdCmColor();
                        odCmColor.setRGB(byte.Parse(array[0]), byte.Parse(array[1]), byte.Parse(array[2]));
                        odDbLayerTableRecord.setColor(odCmColor);
                    }

                    return true;
                }

                throw new Exception("图层或者线型不存在请检查！");
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        public bool GetBlockState(string recordName)
        {
            OdDbBlockTable odDbBlockTable = (OdDbBlockTable)m_database.getBlockTableId().safeOpenObject(OpenMode.kForRead);
            if (!odDbBlockTable.has(recordName))
            {
                return false;
            }

            return true;
        }

        internal void CreateBlockTableRecord(string recordName, List<OdDbEntity> ents)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            try
            {
                OdDbBlockTable odDbBlockTable = (OdDbBlockTable)m_database.getBlockTableId().safeOpenObject(OpenMode.kForRead);
                if (!odDbBlockTable.has(recordName))
                {
                    OdDbBlockTableRecord odDbBlockTableRecord = OdDbBlockTableRecord.createObject();
                    odDbBlockTableRecord.setName(recordName);
                    for (int i = 0; i < ents.Count; i++)
                    {
                        odDbBlockTableRecord.appendOdDbEntity(ents[i]);
                    }

                    odDbBlockTable.upgradeOpen();
                    odDbBlockTable.add(odDbBlockTableRecord);
                    odDbBlockTable.downgradeOpen();
                    return;
                }

                throw new Exception("块表名称已经存在,不能再插入块表！");
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        internal void InsertBlockTableRecord(OdBlockModel odBlock)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            try
            {
                OdDbBlockTable odDbBlockTable = (OdDbBlockTable)m_database.getBlockTableId().safeOpenObject(OpenMode.kForRead);
                if (odDbBlockTable.has(odBlock.BlockName))
                {
                    OdDbBlockReference odDbBlockReference = OdDbBlockReference.createObject();
                    odDbBlockReference.setPosition(new OdGePoint3d(odBlock.Position.get_X(), odBlock.Position.get_Y(), odBlock.Position.get_Z()));
                    odDbBlockReference.setBlockTableRecord(odDbBlockTable.getAt(odBlock.BlockName));
                    if (!GetLayerState(odBlock.LayerName))
                    {
                        throw new Exception("图层' " + odBlock.LayerName + " '不存在,请先创建图层！");
                    }

                    odDbBlockReference.setDatabaseDefaults(m_database);
                    odDbBlockReference.setLayer(odBlock.LayerName, doSubents: true);
                    odDbBlockReference.setRotation(odBlock.Rotating);
                    if (odBlock.Scale != null)
                    {
                        odDbBlockReference.setScaleFactors(odBlock.Scale);
                    }

                    if (odBlock.Mirror != null)
                    {
                        OdGeMatrix3d odGeMatrix3d = new OdGeMatrix3d();
                        odGeMatrix3d.setToMirroring(odBlock.Mirror);
                        odDbBlockReference.transformBy(odGeMatrix3d);
                    }

                    odDbBlockReference.SetExtendId(odBlock.ExtendId);
                    AppendEntityToDatabase(m_database, odDbBlockReference);
                    if (odBlock.Parameters != null && odBlock.Parameters.Count != 0)
                    {
                        odDbBlockReference.SetParameter(odBlock.Parameters);
                    }

                    return;
                }

                throw new Exception(odBlock.BlockName + " 块记录不存在！");
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        internal OdDbObjectId GetBlockOdDbObjectId(string recordName)
        {
            OdDbBlockTable odDbBlockTable = (OdDbBlockTable)m_database.getBlockTableId().safeOpenObject(OpenMode.kForRead);
            return odDbBlockTable.getAt(recordName);
        }

        internal void CopyBlockFromFile(OdBlockModel odBlock)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            try
            {
                if (!File.Exists(odBlock.FileName))
                {
                    throw new Exception("块文件" + odBlock.FileName + "文件不存在！");
                }

                OdDbBlockTable odDbBlockTable = (OdDbBlockTable)m_database.getBlockTableId().safeOpenObject(OpenMode.kForWrite);
                if (!odDbBlockTable.has(odBlock.BlockName))
                {
                    ExHostAppServices exHostAppServices = new ExHostAppServices();
                    OdDbDatabase pSource = exHostAppServices.readFile(odBlock.FileName);
                    if ((m_database.getBlockTableId().safeOpenObject(OpenMode.kForRead) as OdDbBlockTable).has(odBlock.BlockName))
                    {
                        OdDbObjectId odDbObjectId = m_database.insert(odBlock.BlockName, odBlock.BlockName, pSource);
                    }
                    else
                    {
                        OdDbObjectId odDbObjectId2 = m_database.insert(odBlock.BlockName, pSource);
                    }

                    return;
                }

                throw new Exception("块名称已经存在！");
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        public bool GetIsHaveTextStyle(string textStyleName)
        {
            OdDbTextStyleTable odDbTextStyleTable = (OdDbTextStyleTable)Database.getTextStyleTableId().safeOpenObject(OpenMode.kForRead);
            if (odDbTextStyleTable.has(textStyleName))
            {
                return true;
            }

            return false;
        }

        public OdDbObjectId GetTextStyleOBid(string textStyleName)
        {
            OdDbTextStyleTable odDbTextStyleTable = (OdDbTextStyleTable)Database.getTextStyleTableId().safeOpenObject(OpenMode.kForRead);
            return odDbTextStyleTable.getAt(textStyleName);
        }

        internal OdDbObjectId AddTextStyle(DimTextModel dimTextModel)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            try
            {
                OdDbTextStyleTable odDbTextStyleTable = (OdDbTextStyleTable)Database.getTextStyleTableId().safeOpenObject(OpenMode.kForRead);
                odDbTextStyleTable.upgradeOpen();
                OdDbTextStyleTableRecord odDbTextStyleTableRecord = OdDbTextStyleTableRecord.createObject();
                odDbTextStyleTableRecord.setName(dimTextModel.Name);
                odDbTextStyleTableRecord.setFileName(dimTextModel.FileName);
                odDbTextStyleTableRecord.setBigFontFileName(dimTextModel.BigFontFileName);
                odDbTextStyleTableRecord.setTextSize(0.0);
                odDbTextStyleTableRecord.setXScale(dimTextModel.Factor);
                OdDbObjectId result = odDbTextStyleTable.add(odDbTextStyleTableRecord);
                odDbTextStyleTable.downgradeOpen();
                return result;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        public bool GetIsHaveDimStyle(string dimStyleName)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            try
            {
                OdDbDimStyleTable odDbDimStyleTable = (OdDbDimStyleTable)Database.getDimStyleTableId().safeOpenObject(OpenMode.kForRead);
                if (odDbDimStyleTable.has(dimStyleName))
                {
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        public OdDbObjectId GetIsdimStyleOBid(string dimStyleName)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            try
            {
                OdDbDimStyleTable odDbDimStyleTable = (OdDbDimStyleTable)Database.getDimStyleTableId().safeOpenObject(OpenMode.kForRead);
                return odDbDimStyleTable.getAt(dimStyleName);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        internal OdDbObjectId AddDimStyle(DimStyleModel dimStyleModel)
        {
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            try
            {
                OdDbDimStyleTableRecord odDbDimStyleTableRecord = OdDbDimStyleTableRecord.createObject();
                odDbDimStyleTableRecord.setName(dimStyleModel.DimStyleName);
                OdDbDimStyleTable odDbDimStyleTable = (OdDbDimStyleTable)Database.getDimStyleTableId().safeOpenObject(OpenMode.kForRead);
                odDbDimStyleTable.upgradeOpen();
                OdDbObjectId result = odDbDimStyleTable.add(odDbDimStyleTableRecord);
                OdDbObjectId dimtxsty = new OdDbHardPointerId(Database.getTextStyleStandardId());
                if (!string.IsNullOrEmpty(dimStyleModel.DimtxstyName))
                {
                    OdDbTextStyleTable odDbTextStyleTable = (OdDbTextStyleTable)Database.getTextStyleTableId().safeOpenObject(OpenMode.kForRead);
                    dimtxsty = odDbTextStyleTable.getAt(dimStyleModel.DimtxstyName);
                }

                odDbDimStyleTableRecord.setDimtxsty(dimtxsty);
                odDbDimStyleTableRecord.setDimsah(val: true);
                if (dimStyleModel.Dimblk1 != 0)
                {
                    odDbDimStyleTableRecord.setDimblk1(dimStyleModel.Dimblk1.ToString());
                }

                if (dimStyleModel.Dimblk2 != 0)
                {
                    odDbDimStyleTableRecord.setDimblk2(dimStyleModel.Dimblk2.ToString());
                }

                odDbDimStyleTableRecord.setDimasz(dimStyleModel.Dimasz);
                odDbDimStyleTableRecord.setDimlwd(dimStyleModel.Dimlwd);
                odDbDimStyleTableRecord.setDimlwe(dimStyleModel.Dimlwe);
                odDbDimStyleTableRecord.setDimsd1(dimStyleModel.Dimsd1);
                odDbDimStyleTableRecord.setDimsd2(dimStyleModel.Dimsd2);
                odDbDimStyleTableRecord.setDimclrd(Common.RgbToOdCmColor(dimStyleModel.Dimclrd));
                OdDbLinetypeTable odDbLinetypeTable = (OdDbLinetypeTable)m_database.getLinetypeTableId().safeOpenObject();
                OdDbObjectId at = odDbLinetypeTable.getAt(dimStyleModel.Dimltype);
                odDbDimStyleTableRecord.setDimltype(at);
                odDbDimStyleTableRecord.setDimdle(dimStyleModel.Dimdle);
                odDbDimStyleTableRecord.setDimltex1(odDbLinetypeTable.getAt(dimStyleModel.Dimltex1));
                odDbDimStyleTableRecord.setDimltex2(odDbLinetypeTable.getAt(dimStyleModel.Dimltex2));
                odDbDimStyleTableRecord.setDimse1(dimStyleModel.Dimse1);
                odDbDimStyleTableRecord.setDimse2(dimStyleModel.Dimse2);
                odDbDimStyleTableRecord.setDimfxlon(dimStyleModel.Dimfxlon);
                odDbDimStyleTableRecord.setDimfxl(dimStyleModel.Dimfxl);
                odDbDimStyleTableRecord.setDimclre(Common.RgbToOdCmColor(dimStyleModel.Dimclre));
                odDbDimStyleTableRecord.setDimexe(dimStyleModel.Dimexe);
                odDbDimStyleTableRecord.setDimexo(dimStyleModel.Dimexo);
                odDbDimStyleTableRecord.setDimtfillclr(Common.RgbToOdCmColor(dimStyleModel.Dimtfillclr));
                odDbDimStyleTableRecord.setDimclrt(Common.RgbToOdCmColor(dimStyleModel.Dimclrt));
                odDbDimStyleTableRecord.setDimtxt(dimStyleModel.Dimtxt);
                odDbDimStyleTableRecord.setDimgap(dimStyleModel.Dimgap);
                odDbDimStyleTableRecord.setDimtoh(dimStyleModel.Dimtoh);
                odDbDimStyleTableRecord.setDimlim(dimStyleModel.Dimlim);
                odDbDimStyleTableRecord.setDimtad(dimStyleModel.Dimtad);
                odDbDimStyleTableRecord.setDimtih(dimStyleModel.Dimtih);
                odDbDimStyleTableRecord.setDimscale(dimStyleModel.Dimscale);
                odDbDimStyleTableRecord.setDimdec(dimStyleModel.Dimdec);
                odDbDimStyleTableRecord.setDimtix(dimStyleModel.Dimtix);
                odDbDimStyleTableRecord.setDimsoxd(dimStyleModel.Dimsoxd);
                odDbDimStyleTableRecord.setDimtmove(dimStyleModel.Dimtmove);
                odDbDimStyleTableRecord.setDimtofl(dimStyleModel.Dimtofl);
                odDbDimStyleTable.downgradeOpen();
                return result;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                MemoryManager.GetMemoryManager().StopTransaction(value);
            }
        }

        internal OdDbObjectId GetArrowTypeOdDbObjectId(string arrName)
        {
            OdDbBlockTable odDbBlockTable = (OdDbBlockTable)m_database.getBlockTableId().safeOpenObject(OpenMode.kForRead);
            return odDbBlockTable.getAt(arrName);
        }

        public void Dispose()
        {
        }
    }
}